
package ebasclient.abstracts.guielements;


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.List;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author Luca Coraci
 */
public abstract class MyAbstractTableModel<T> extends AbstractTableModel implements Reorderable, PropertyChangeListener {

    private static final long serialVersionUID = 1L;
    public static final String MOVE_UP = "move_up";
    public static final String MOVE_DOWN = "move_down";
    private List<T> data = new LinkedList<T>();
    private final String[] labels;

    public MyAbstractTableModel(String[] labels, List<T> datas) {
        if(datas != null)
            this.data = datas;
        this.labels = labels;
    }

    public List<T> getData()
    {
        return data;
    }

    public int size(){
        return this.data.size();
    }

    public final String [] getHeaderLabels(){
        return labels;
    }

    public T getElementAt(int row){
        return row >= 0 && row < data.size() ? this.data.get(row) : null;
    }

    public T getLast(){
        return this.data.isEmpty() ? null : this.data.get(this.data.size() -1);
    }

    public T getFirst(){
        return this.data.isEmpty() ? null : this.data.get(0);
    }


    public synchronized void addRowElement(T element) {
        data.add(element);
        fireTableRowsInserted(data.size() - 1, data.size() - 1);

    }
    
    public synchronized void addRowElementOnHead(T element) {
        ((LinkedList)data).addFirst(element);
        fireTableRowsInserted(0, 0);

    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public int getColumnCount() {
        return labels.length;
    }

    @Override
    public String getColumnName(int column) {
        return labels[column];
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return false;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        //miss some code...
        fireTableCellUpdated(row, col);
    }

    public int indexOf(T t)
    {
        return data.indexOf(t);
    }

    @SuppressWarnings("unchecked")
    public int indexOfObject(Object o){
        return data.indexOf((T)o);
    }

    @Override
    public void reorder(int fromIndex, int toIndex) {
        T element = data.get(fromIndex);
        data.set(fromIndex, data.get(toIndex));
        data.set(toIndex, element);

        fireTableRowsUpdated(toIndex, toIndex);
        fireTableRowsUpdated(fromIndex, fromIndex);

    }
    
    public synchronized void clearModel(){
        int c = 0;
        int cccc = data.size();
        for (int i = 0; i < cccc; i++) {
            removeRowElement(0);
            c++;
        }
    }

    public synchronized  void removeRowElement(int i) {
        data.remove(i);
        fireTableRowsDeleted(i, i);
        // fireTableDataChanged();
//        for(int row = i; row < datas.size()-1;row++) {
//            fireTableCellUpdated(row, 0);
//        }
    }

    /**
     * remove the element i from the data list without firing the event "RowsDeleted"
     * @param i
     */
    public void simpleRemove(int i){
        data.remove(i);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(MOVE_UP)) {
            Integer index  = data.indexOf(evt.getNewValue());
            if (index == 0) {
                return;
            } else {
                reorder(index, index - 1);
            }
        }
        if (evt.getPropertyName().equals(MOVE_DOWN)) {
            Integer index  = data.indexOf(evt.getNewValue());
            if (index >= data.size() - 1) {
                return;
            } else {
                reorder(index , index+1);
            }
        }
    }

    public void refreshRow(int index){
        fireTableRowsUpdated(index, index);
    }

    @Override
    public abstract Object getValueAt(int rowIndex, int columnIndex);

    public void refreshByObjectField(Object obj){
        //Ovverride it when you need
    }

}
